/*
 * BlackLightning.PluginLib.Modules.Packets.CommandPacket
 * Andy Tidball
 * 
 * Project: Black Lightning Plugin Library
 * Copyright: GNU General Public License
 */

using System;
using System.Text.RegularExpressions;

namespace BlackLightning.PluginLib.Modules.Packets {
    /// <summary>
    /// A packet that represents a command.
    /// </summary>
    [Serializable]
    public abstract class CommandPacket : BLPacket {
        // member data
        private string   _Command; // the command being issued
        private string[] _Args;    // arguments passed to the command

        /// <summary>
        /// Creates a new CommandPacket.
        /// </summary>
        /// <param name="Source">The program that the packet came from.</param>
        /// <param name="Destination">The program that the packet will be delivered to.</param>
        /// <param name="Data">The data string the packet was parsed from.</param>
        /// <param name="Command">The command to contain in the packet.</param>
        /// <param name="Arguments">The arguments given to the command contained in the packet.</param>
        protected CommandPacket(Program Source, Program Destination, string Data, string Command, string[] Arguments)
            : base(Source, Destination, Data) {
            _Command = Command;
            _Args    = Arguments;
        }

        /// <summary>
        /// Copy constructor.
        /// </summary>
        /// <param name="P">The CommandPacket to create a copy of.</param>
        /// <param name="DeepCopyOrNextState">True to make a deep copy of the given packet, false to instead use the given packet as the new packet's previous state.</param>
        protected CommandPacket(CommandPacket P, bool DeepCopyOrNextState)
            : base(P, DeepCopyOrNextState) {
            _Command = P._Command;
            _Args = new string[P._Args.Length];
            P._Args.CopyTo(_Args, 0);
        }

        /// <summary>
        /// Gets or sets the command contained in the packet.
        /// </summary>
        public string Command {
            get {
                return _Command;
            }
            set {
                _Command = value;
            }
        }

        /// <summary>
        /// Gets or sets the arguments sent to the command.
        /// </summary>
        public string[] Arguments {
            get {
                return _Args;
            }
            set {
                _Args = value;
            }
        }
    }

    /// <summary>
    /// A filter for CommandPackets.
    /// </summary>
    [Serializable]
    public class CommandPacketFilter : BLPacketFilter {
        // member data
        private string   _CommandString = null; // the string to match against the packet's command
        private Regex    _CommandRegex  = null; // the regular expression to match against the packet's command
        private string[] _ArgStrings    = null; // an array of strings to match against the packet's arguments
        private Regex[]  _ArgRegexes    = null; // an array of regular expressions to match against the packet's arguments

        /// <summary>
        /// Creates a new CommandPacketFilter.
        /// </summary>
        /// <param name="Command">The string to match against the packet's command.</param>
        public CommandPacketFilter(string Command) {
            _CommandString = Command;
        }

        /// <summary>
        /// Creates a new CommandPacketFilter.
        /// </summary>
        /// <param name="Command">The regular expression to match against the packet's command.</param>
        public CommandPacketFilter(Regex Command) {
            _CommandRegex = Command;
        }

        /// <summary>
        /// Creates a new CommandPacketFilter.
        /// </summary>
        /// <param name="Command">The string to match against the packet's command.</param>
        /// <param name="Arguments">An array of strings to match against the packet's arguments.</param>
        public CommandPacketFilter(string Command, string[] Arguments) {
            _CommandString = Command;
            _ArgStrings = Arguments;
        }

        /// <summary>
        /// Creates a new CommandPacketFilter.
        /// </summary>
        /// <param name="Command">The regular expression to match against the packet's command.</param>
        /// <param name="Arguments">An array of regular expressions to match against the packet's commands.</param>
        public CommandPacketFilter(Regex Command, Regex[] Arguments) {
            _CommandRegex = Command;
            _ArgRegexes = Arguments;
        }

        /// <summary>
        /// Creates a new CommandPacketFilter.
        /// </summary>
        /// <param name="Source">The source program to match against the packet's source.</param>
        /// <param name="Destination">The destination program to match against the packet's destination.</param>
        public CommandPacketFilter(Program Source, Program Destination)
            : base(Source, Destination) {
        }

        /// <summary>
        /// Creates a new CommandPacketFilter.
        /// </summary>
        /// <param name="Source">The source program to match against the packet's source.</param>
        /// <param name="Destination">The destination program to match against the packet's destination.</param>
        /// <param name="Command">The string to match against the packet's command.</param>
        public CommandPacketFilter(Program Source, Program Destination, string Command)
            : base(Source, Destination) {
            _CommandString = Command;
        }

        /// <summary>
        /// Creates a new CommandPacketFilter.
        /// </summary>
        /// <param name="Source">The source program to match against the packet's source.</param>
        /// <param name="Destination">The destination program to match against the packet's destination.</param>
        /// <param name="Command">The regular expression to match against the packet's command.</param>
        public CommandPacketFilter(Program Source, Program Destination, Regex Command)
            : base(Source, Destination) {
            _CommandRegex = Command;
        }

        /// <summary>
        /// Creates a new CommandPacketFilter.
        /// </summary>
        /// <param name="Source">The source program to match against the packet's source.</param>
        /// <param name="Destination">The destination program to match against the packet's destination.</param>
        /// <param name="Command">The string to match against the packet's command.</param>
        /// <param name="Arguments">An array of strings to match against the packet's arguments.</param>
        public CommandPacketFilter(Program Source, Program Destination, string Command, string[] Arguments)
            : base(Source, Destination) {
            _CommandString = Command;
            _ArgStrings = Arguments;
        }

        /// <summary>
        /// Creates a new CommandPacketFilter.
        /// </summary>
        /// <param name="Source">The source program to match against the packet's source.</param>
        /// <param name="Destination">The destination program to match against the packet's destination.</param>
        /// <param name="Command">The regular expression to match against the packet's command.</param>
        /// <param name="Arguments">An array of regular expressions to match against the packet's commands.</param>
        public CommandPacketFilter(Program Source, Program Destination, Regex Command, Regex[] Arguments)
            : base(Source, Destination) {
            _CommandRegex = Command;
            _ArgRegexes = Arguments;
        }

        /// <summary>
        /// Gets or sets the string to match against the packet's command.
        /// </summary>
        public string CommandString {
            get {
                return _CommandString;
            }
            set {
                _CommandString = value;
            }
        }

        /// <summary>
        /// Gets or sets the regular expression to match against the packet's command.
        /// </summary>
        public Regex CommandRegex {
            get {
                return _CommandRegex;
            }
            set {
                _CommandRegex = value;
            }
        }

        /// <summary>
        /// Gets or sets the strings to match against the packet's arguments.
        /// </summary>
        public string[] ArgumentStrings {
            get {
                return _ArgStrings;
            }
            set {
                _ArgStrings = value;
            }
        }

        /// <summary>
        /// Gets or sets the regular expressions to match against the packet's arguments.
        /// </summary>
        public Regex[] ArgumentRegexes {
            get {
                return _ArgRegexes;
            }
            set {
                _ArgRegexes = value;
            }
        }

        /// <summary>
        /// Matches the packet's dynamic data against the filter.
        /// </summary>
        /// <param name="Packet">The packet to match against the filter.</param>
        /// <returns>True if the packet's dynamic data matches the current setup of the filter, false if it does not.</returns>
        public override bool DynamicMatch(BLPacket Packet) {
            // make sure this is a CommandPacket
            CommandPacket P = Packet as CommandPacket;
            if (P == null) {
                return false;
            }

            // match the command
            if (_CommandString != null && _CommandString != P.Command) {
                return false;
            }
            if (_CommandRegex != null && !_CommandRegex.IsMatch(P.Command.Replace(Environment.NewLine, "\n"))) {
                return false;
            }

            // match the arguments
            if (_ArgStrings != null) {
                if (_ArgStrings.Length > P.Arguments.Length) {
                    return false;
                }
                for (int i = 0; i < _ArgStrings.Length; ++i) {
                    if (_ArgStrings[i] != P.Arguments[i]) {
                        return false;
                    }
                }
            }
            if (_ArgRegexes != null) {
                if (_ArgRegexes.Length > P.Arguments.Length) {
                    return false;
                }
                for (int i = 0; i < _ArgRegexes.Length; ++i) {
                    if (!_ArgRegexes[i].IsMatch(P.Arguments[i].Replace(Environment.NewLine, "\n"))) {
                        return false;
                    }
                }
            }

            // everything passed, match the base packet data
            return base.DynamicMatch(P);
        }
    }
}
